﻿//	Plazes-ASPI is an AS2.0 abstraction of the Plazes (http://www.plazes.com) XMLRPC-API
//		Copyright (C) 2006	Florian Mlodzik
//
//		This library is free software; you can redistribute it and/or
//		modify it under the terms of the GNU Lesser General Public
//		License as published by the Free Software Foundation; either
//		version 2.1 of the License, or (at your option) any later version.
//
//		This library is distributed in the hope that it will be useful,
//		but WITHOUT ANY WARRANTY; without even the implied warranty of
//		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the GNU
//		Lesser General Public License for more details.
//
//		You should have received a copy of the GNU Lesser General Public
//		License along with this library; if not, write to the Free Software
//		Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

// svn:keywords
// $URL: http://plazes-aspi.googlecode.com/svn/trunk/src/as2/com/orthogeneric/webapis/plazes/rpc/RPCall.as $
// $Id: RPCall.as 4 2006-07-29 09:33:20Z florian.mlodzik $

/**
* The RPCall-class provides a local interface to instigate remote procedure calls to the <a href="http://beta.plazes.com/api/plazes/">PlazesApi</a>.
* It is a publicly static implementation used internally by the MethodsBase subclasses to call remote methods.	
* 
* @author florian.mlodzik@gmail.com
* @version 1.0b
*/

// import -->
import ascb.util.Proxy;
import com.orthogeneric.net.xmlrpc.XmlRpc;
import com.orthogeneric.net.xmlrpc.events.XmlRpcResult;
import com.orthogeneric.net.xmlrpc.events.XmlRpcError;
import com.orthogeneric.webapis.plazes.PlazesService;
import com.orthogeneric.webapis.plazes.methods.MethodsBase;
import com.orthogeneric.webapis.plazes.events.PlazesResult;
import com.orthogeneric.webapis.plazes.events.PlazesFault;
import com.orthogeneric.webapis.plazes.events.PlazesError;
// <-- import

class com.orthogeneric.webapis.plazes.rpc.RPCall 
{
	/** The boolean whether to queue calls for sequential processing */
	private static var _queueCalls:Boolean = false;
	/** The array acting as a fifo stack */ 
	private static var _callQueue:Array = new Array();
	/** The boolean for a rpc in progress */	
	private static var _callPending:Boolean = false;

	/** The instance variable holding a XmlRpc-instance */
	private var _xmlRpc:XmlRpc;

	/**
	* The private RPCall-class constructor.
	* RPCall-instances are constructed through the static invoke method. Each instance represents and processes one rpc.
	* 
	* @param target The PlazesService-instance the instigation of the rpc originated from
	* @param callParams The array containing the arguments for the remote method
	* @param lMethod An identifier of the local method that was called and instigated a rpc
	* @see invoke()
	* @exclude
	*/
	private function RPCall(target:PlazesService, callParams:Array, lMethod:String, methGroup:String)
	{
		_xmlRpc = new XmlRpc(PlazesService.ENDPOINT);
		// delegate event-methods
		_xmlRpc.onXmlRpcResult = Proxy.create(this, this._onApiResult, target, lMethod, methGroup)
		_xmlRpc.onXmlRpcError = Proxy.create(this, this._onApiError, target, lMethod, methGroup)
		// do the xmlrpc
		_xmlRpc.callMethod.apply(_xmlRpc, callParams);
	}

	/**
	* The class-method to invoke a remote procedure call. 
	* 
	* @param target The MethodsBase-subclass instigating the rpc
	* @param lMethod An identifier for the local method that was called and instigated a rpc
	* @param rMethod The name of the remote PlazesApi-method 
	* @param (optional) Any number of paramters for the remote method
	*/
	public static function invoke(target:MethodsBase, lMethod:String, rMethod:String)
	{
		if (!_callPending) { // if we don't queue calls it will always be false  		
			if (_queueCalls) { // do we queue calls?
				_callPending = true; // we process, so it's pending 
			}
			//trace("invoke: "+target.group+"-"+lMethod+"-"+rMethod)
			
			// collect params for the rpc
			var methGroup:String = target.group;
			var devKey:String = target.service.devKey;
			var uname:String = target.service.username;
			var passwd:String = target.service.passwordMD5;
			var callParams:Array = new Array(rMethod, devKey, uname, passwd); // the first 4 will always be the same
					callParams = callParams.concat(arguments.splice(3)); // add the additional arguments for the remote method
			// actually invoke the remote method
			var xRpc:RPCall = new RPCall(target.service, callParams, lMethod, methGroup); 	 
		} else {
			_callQueue.push(arguments); // some call pending so we queue upon the stack  
		} 
	}

	/**
	* The class-variable depicting whether remote calls shall be invoked sequentially.
	* Implemented as getter/setter function.
	* 
	* @see PlazesService#queueCalls
	*/
	public static function get queue():Boolean
	{
		return _queueCalls;  
	}
	public static function set queue(q:Boolean):Void
	{
		if (!q && _queueCalls) { // change from true to false?
			_callQueue = new Array();
			_callPending = false; 
		}
		_queueCalls = q;  
	}

	/**
	* The class-method to invoke the first queued remote procedure call. 
	* 
	* @exclude
	*/
	private static function _invokeQueued():Void
	{
		_callPending = false;
		if (_callQueue.length > 0) {
			var applyParams:Array = _callQueue.splice(0, 1)[0]; // "shift" arguments from stack 
			invoke.apply(RPCall, applyParams); // invoke "again"	
		}
	}

	/**
	* The instance event handler called upon a successful XmlRpc-response 
	*
	* @param evt The XmlRpcResult event
	* @param target A MethodsBase subclass that instigated the remote call
	* @param lMethod An identifier of the local method that was initially called and instigated a rpc
	* 
	* @see RPCall()
	* @see XmlRpcResult
	* @exclude
	*/
	private function _onApiResult(evt:XmlRpcResult, target:PlazesService, lMethod:String, methGroup:String)
	{
		if (evt.result.faultCode == undefined) { // it is not a fault result
			target.dispatchEvent( new PlazesResult(target, evt, lMethod, methGroup) );
		} else {
			target.dispatchEvent( new PlazesFault(target, evt, lMethod, methGroup) );  
		}
		_invokeQueued(); // check the queue  
	}

	/**
	* The instance event handler called upon a failed XmlRpc 
	*
	* @param evt The XmlRpcError event
	* @param target A MethodsBase subclass that instigated the remote call
	* @param lMethod An identifier of the local method that was initially called and instigated a rpc
	* 
	* @see RPCall()
	* @see XmlRpcResult
	* @exclude
	*/
	private function _onApiError(evt:XmlRpcError, target:PlazesService, lMethod:String, methGroup:String)
	{
		target.dispatchEvent( new PlazesError(target, evt, lMethod, methGroup) );
		_invokeQueued(); // check the queue
	}
}